<?php


namespace app\common\service\order\coupon_order;


use api\channel\jutuike\Coupon;
use api\channel\jutuike\TravelUnion;
use api\channel\jutuike\Union;
use api\channel\meituan\alliance\MeituanAllianceBase;
use api\channel\meituan\alliance\Seckill;
use api\channel\meituan\alliance\Takeout;
use api\channel\taobao\EleOrderChannel;
use app\common\service\order\coupon_order\jutuike_channel\JutuikeChannelBase;
use app\common\service\order\coupon_order\meituan\MeituanChannelBase;
use app\common\service\order\coupon_order\meituan_takeout\MeituanTakeoutBase;
use app\common\service\order\coupon_order\meituan_takeout\MeituanTakeoutSyncOrder;
use app\common\service\order\coupon_order\taobao\EleTaobao;
use app\model\Agent;
use app\model\AgentChannel;
use app\model\AgentSalesman;
use app\model\AgentServiceConfig;
use app\model\BaseSupplier;
use app\model\CouponOrder;
use app\model\CouponOrderSid;
use Carbon\Carbon;
use think\db\Query;
use think\Exception;
use think\facade\Db;
use think\helper\Str;
use think\Log;

/**
 * 除了聚推客之外的平台计算 这个只是做一个示例，如果需要扩展，参考  app\common\service\order\coupon_order\jutuike_channel\JutuikeChannelBase.php
 * Class Base
 * @package app\common\service\order\coupon_order
 * @property-read $supplier_id
 * @property-read $order_id
 * @property-read $amount
 * @property-read $settle_price
 * @property-read $supplier_price
 * @property-read $profit
 * @property-read $agent_id
 * @property-read $settle_type
 * @property-read $platform_profit
 * @property-read $origin_amount
 * @property-read $pay_amount
 * @property-read $pay_status
 * @property-read $pay_time
 * @property-read $user_id
 * @property-read $settled_at
 * @property-read $status
 * @property-read $supplier_order_sn
 * @property-read $agent_settle_status
 * @property-read $product_name
 * @property-read $product_image
 * @property-read $type 常量类型
 * @property-read $serv_type
 * @property-read $agent_settle_discount //代理商的结算折扣
 * @property-read $order_all_commission //这笔订单的所有佣金
 * @property-read $supplier_code
 * @property-read $cnid//渠道
 * @property-read $status_desc //状态详情
 * @property-read $salesman_id //业务员
 * @property-read $order_created_at //下单时间
 * @property-read $ext_data //扩展数据
 * @property-read $title //标题
 * @property-read $refund_status //退款状态
 * @property-read $sid //退款状态
 * @property-read $out_order_id //退款状态
 * @property-read $mobile //手机号
 * @property-read $refund_amount //退款金额
 * @property-read $account //账号
 * @property-read $quote_id //对应表中的记录
 * @property-read $template_id //模板id
 * @property-read $create_order_from //下单来源
 * @property-read $brand_id //品牌idcpsid
 */
class Base
{

    const WARNING_CODE = 100;
    const INFO_CODE = 200;


    protected $_agent_id = 0; //sid 中的代理信息
    protected $_channel_id = 0; //sid渠道
    protected $_user_id = 0; //sid 用户
    protected $_income_type = 1; //代理是否自己配置的接口 AgentServiceConfig:: 枚举;

    /**
     * @var CouponOrderSid $couponOrderSid
     */
    protected $couponOrderSid;//标识

    /**
     * @var MeituanAllianceBase $extend
     */
    public $extend;
    /**
     * @var \api\channel\jutuike\Base $extend
     */

    public $exist_fileld = 'supplier_order_sn';
    /**
     * 第三方返回的信息
     * @var
     */
    public $params;


    /**
     * 错误信息
     */
    public $error;

    /**
     * 获取属性
     * @param $name
     * @param $arguments
     * @return mixed
     * @throws Exception
     */
    public function __get($name)
    {

        $method_name = 'get' . Str::studly($name);

        if (!method_exists($this, $method_name)) throw new Exception('渠道未配置' . $name);

        return $this->$method_name();
    }

    /**
     * 设置第三方
     * //      * @param \api\channel\jutuike\Base $extend
     */
    public function setExtendApi($extend)
    {
        $this->extend = $extend;
        return $this;
    }


    /**
     * @param mixed $params
     */
    public function setParams($params)
    {
        $this->params = $params;
        return $this;
    }

    /**
     * 公用获取供应商id
     */
    public function getSupplierId()
    {

        if (empty($this->extend)) {
            throw new Exception('未配置第三方渠道');
        }

        if (empty($this->extend->supplierInfo)) {
            throw new Exception('未赋值供应商信息');
        }

        return $this->extend->supplierInfo->id;

    }

    /**
     * 代理结算比例
     */
    public function getAgentSettleDiscount()
    {
        if ($this->_income_type == AgentServiceConfig::INCOME_TYPE_SELF) {//接口的全部返回给代理
            return 100;
        }

        $discount = AgentServiceConfig::where('agent_id', $this->agent_id)
            ->where('serv_type', $this->serv_type)
            ->where('status', 1)
//            ->cache('AgentServiceConfigSyncId', 2)
            ->value('value', 0);

        return floatval($discount);

    }

    /**
     * 公共start
     * 本地存储订单号 自由发挥
     */
    public function getOrderId()
    {

        return $this->supplier_id . $this->supplier_order_sn . random_int(1000, 9999);

    }

    /**
     * 代理商利润
     */
    public function getProfit()
    {

        return intval(strval($this->getOrderAllCommission() * $this->getAgentSettleDiscount()));

    }

    /**
     * 平台利润
     */
    public function getPlatformProfit()
    {

        $platFormProfit = yuan2fen($this->getOrderAllCommission()) - $this->getProfit(); // 平台利润,这个profit 已经* 99% 按照99来算了所以不需要乘了


        if ($platFormProfit < 0) {
            $dis = $this->getAgentSettleDiscount();
            $profit = $this->getProfit() / 100;
            throw new Exception('亏死了，平台利润小于0,第三方分佣：' . $this->getOrderAllCommission() . '分给代理的：' . $profit . '代理折扣：' . $dis . '这个就要问运营了，为什么要这么设计，最好不要这样agent_service_config 表存折扣');

        }

        return $platFormProfit;
    }

    /**
     * 结算价格 订单金额-代理商利润 = 代理商看到的成本价
     */
    public function getSettlePrice()
    {

        return $this->getAmount() - $this->getProfit();

    }

    /**
     * 公共send
     *
     * 供应商结算金额  订单金额-代理商利润-平台利润
     */
    public function getSupplierPrice()
    {

        return $this->amount - $this->profit - $this->platform_profit;

    }

    /**
     * 获取业务员
     */
    public function getSalesmanId()
    {

        return AgentSalesman::getSalesmanIdByAgentId($this->agent_id, $this->serv_type);

    }

    public function getSupplierCode()
    {
        return $this->extend->supplierInfo->code;
    }

    //渠道id
    public function getCnid()
    {
        return $this->_channel_id;
    }

    //结算时间
    public function getSettledAt()
    {
        $pay_time = $this->pay_time;
        if (empty($pay_time)) {
            return null;
        }

        //下个月25号
        return $this->getSettleDate($this->pay_time);
    }

    //用户id
    public function getUserId()
    {
        return $this->_user_id;
    }

    public function getAgentId()
    {
        if (!Agent::find($this->_agent_id)) {
            $msg = '代理商不存在，过滤了';
            echo $msg . PHP_EOL;
            \think\facade\Log::info($msg);
            throw new Exception($msg);
        };

        return $this->_agent_id;
    }


    /**
     * 退款金额
     */
    public function getRefundAmount()
    {
        return 0;
    }

    /**
     * 模板
     */
    public function getTemplateId()
    {


        $agentChannel = AgentChannel::query()
            ->where('id', $this->_channel_id)
            ->find();

        if (empty($agentChannel)) {
            return 0;
        }

        return $agentChannel->template_id;

    }

    /**
     * 根据支付时间，获取结算时间
     * 结算时间：次月25号
     */
    protected function getSettleDate($payTime)
    {
        $year = substr($payTime, 0, 4);
        $month = substr($payTime, 5, 2) + 1;
        return date('Y-m-d', mktime(0, 0, 0, $month, 25, $year));
    }

    /**
     *
     */
    public function getMobile()
    {
        return '';
    }

    public function getAccount()
    {
        return $this->params['account'] ?? '';
    }


    /**
     * 渠道标识
     */
    public function processSid()
    {
        if (!empty($this->couponOrderSid)) {
            return;
        }


        //带有 s 标识的处理
        if (strstr($this->sid, 's')) {

            $sid = explode('s', $this->sid);

            $this->_agent_id = $sid[1] ?? 0;
            $this->_channel_id = $sid[2] ?? 0;
            $this->_user_id = $sid[0] ?? 0;
            return;
        }

        //有下划线处理
        if (strstr($this->sid, '_')) {

            list($agentId, $userId, $channel_id) = $this->extend->parseSid($this->sid);
            $this->_agent_id = $agentId;
            $this->_user_id = $userId;
            $this->_channel_id = $channel_id;
            return;
        }
        //纯数字的，是数据库存储的渠道信息
        $sid = $this->sid;
        if (!empty($sid)) {
            /**
             * @var CouponOrderSid $couponSidObj
             */
            $couponSidObj = CouponOrderSid::query()->where('id', $this->sid)->findOrEmpty();

            if (empty($couponSidObj)) {
                return;
            }
            $this->_user_id = $couponSidObj->user_id;
            $this->_channel_id = $couponSidObj->channel_id;
            $this->_agent_id = $couponSidObj->agent_id;
            $this->_income_type = $couponSidObj->income_type;
            $this->couponOrderSid = $couponSidObj;
        }


    }


    /**
     * 整理保存数据
     */
    public function formatSaveData()
    {
        $ext_data = $this->ext_data;  //魔术方法不能用empty判断
        $data = [
            'supplier_id' => $this->supplier_id,
            'order_id' => $this->order_id,
            'type' => $this->type,
            'serv_type' => $this->serv_type,
            'amount' => $this->amount,
            'settle_price' => $this->settle_price,
            'supplier_price' => $this->supplier_price,
            'profit' => $this->profit,
            'agent_id' => $this->agent_id,
            'settle_type' => $this->settle_type,
            'platform_profit' => $this->platform_profit,
            'origin_amount' => $this->origin_amount,
            'pay_amount' => $this->pay_amount,
            'pay_status' => $this->pay_status,
            'pay_time' => $this->pay_time,
            'user_id' => $this->user_id,
            'settled_at' => $this->settled_at, // 次月25号结算
            'status' => $this->status,
            'supplier_order_sn' => $this->supplier_order_sn,
            'agent_settle_status' => $this->agent_settle_status,
            'product_name' => $this->product_name,
            'product_image' => $this->product_image,
            'settle_discount' => $this->agent_settle_discount,
            'supplier_code' => $this->supplier_code,
            'cnid' => $this->cnid,
            'salesman_id' => $this->salesman_id,
            'order_created_at' => $this->order_created_at,
            'ext_data' => !empty($ext_data) ? $ext_data : new \stdClass(), //修改器无法执行到json 格式的  setExtDataAttr
            'title' => $this->title,
            'sid' => $this->sid,
            'out_order_id' => $this->out_order_id,
            'mobile' => $this->mobile,
            'refund_amount' => $this->refund_amount,
            'refund_status' => $this->refund_status,
            'account' => $this->account,
            'quote_id' => $this->quote_id,
            'template_id' => $this->template_id,
            'create_order_from' => $this->create_order_from,
            'brand_id' => $this->brand_id,
//            'status_msg' => $this->status_desc,  //更新状态的时候没有更新这个就尴尬了，就让前端去判断 结算状态就好了
        ];


        return $data;
    }


    /**
     * 保存
     * @return CouponOrder
     */
    public function saveOrder()
    {

        $this->processSid();//一定要钱，不然下面的 serv_type 沒有获取到coupon_serv 的值会报错

        /**
         * @var Query $obj
         */
        $obj = $this->existOrder();


        if (!$obj) {
            try {
                Db::startTrans();

                if (property_exists($this, 'couponOrder')) {
                    /** @var CouponOrder $couponOrder */
                    $obj = $this->couponOrder;
                    $obj->setAttrs($this->formatSaveData());
                } else {

                    $obj = new CouponOrder($this->formatSaveData());

                }


                $obj->log .= date('Y-m-d H:i:s') . '创建订单';
                $obj->save();


                if ($obj->pay_status == CouponOrder::C_PAY_STATUS_YES) {
                    BaseSupplier::query()
                        ->where('id', $this->supplier_id)
                        ->inc('order_count', 1)
                        ->update();
                }
                Db::commit();
            } catch (\Exception $exception) {
                \think\facade\Log::error($exception->getMessage());
                \think\facade\Log::error($exception->getFile());
                \think\facade\Log::error($exception->getLine());
                if (isProd()) {
                    $this->error = $exception->getMessage();
                } else {
                    $this->error = $exception->getMessage() . $exception->getFile() . ":" . $exception->getLine();
                }
                Db::rollback();
            }

        }

        return $obj;
    }

    /**
     * 是否存在订单
     */
    public function existOrder()
    {
        $field = $this->exist_fileld;


        $query = CouponOrder::where($field, $this->{$field});

        if (is_numeric($this->sid)) {
            $query->where('sid', $this->sid); //几乎不考虑供应商订单会重复
        }


        $obj = $query->find();
        return $obj;
    }

    /**
     * 获取订单
     */
    public function httpGetOrder()
    {

        $query = [];

        for ($i = 1; $i < 999; $i++) {
            $query['page'] = $i;
            /**
             * @var TravelUnion
             * @var Coupon
             * @var Seckill
             * @var Takeout
             * @var Union
             */
            $orders = $this->extend->orders($query);


            if (env('APP_ENV') == 'local') {
                var_dump($orders);
            }

            if (empty($orders)) break;

            if (empty($orders['data'])) break;

            foreach ($orders['data'] as $order) {
                //处理单条数据
                $this->handleOneData($order);

            }
            if (!empty($orders['last_page'])) {
                //判断是否已经是最后一页了
                if ($i >= $orders['last_page']) break;
            }

        }
    }

    /**
     * 更新数据库一条数据  每次更新两条数据
     */
    public function updateOrderInfoByOne()
    {

        /**@var CouponOrder $couponOrder */
        CouponOrder::query()
            ->where('serv_type', $this->serv_type)
            ->where('status', CouponOrder::C_STATUS_RECHARGE_SUCCESS)
            ->order('curl_date', 'asc')
            ->limit(1)
            ->select()->each(function (CouponOrder $couponOrder) {
                /**@var CouponOrder $couponOrder */
                $couponOrder->curl_date = Carbon::now();
                $couponOrder->save();

                if (!method_exists($this->extend, 'getOneOrder')) {
                    return;
                }

                $order = $this->extend->getOneOrder($couponOrder);

                $this->handleOneData($order['data'] ?? []);

            });
    }

    /**
     * 处理单条数据
     * @param array $order
     */
    public function handleOneData(array $order)
    {

        /**
         * @var JutuikeChannelBase $obj
         * @var MeituanTakeoutSyncOrder $obj
         * @var MeituanChannelBase $obj
         * @var EleTaobao $obj
         */
        $obj = new $this();

        $obj->_agent_id = $this->_agent_id;
        $obj->_user_id = $this->_user_id;
        $obj->_channel_id = $this->_channel_id;
        try {
            $obj->setExtendApi($this->extend)
                ->setParams($order)
                ->syncOrder();
        } catch (\Exception $exception) {
            $msgs = [
                'msg' => '拉取CPS 订单错误',
                'exception' => $exception->getMessage(),
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
                'httpData' => $order,
                'supplier_name' => $this->extend->supplierInfo->name,
                'supplier_id' => $this->extend->supplierInfo->id,
            ];
            if ($exception->getCode() == self::INFO_CODE) {
                \think\facade\Log::info(json_encode($msgs, JSON_UNESCAPED_UNICODE));
            } else {
                \think\facade\Log::error(json_encode($msgs, JSON_UNESCAPED_UNICODE));
            }

        }
    }

    public function getQuoteId()
    {
        return 0;
    }

    public function getBrandId()
    {
        return 0;
    }

    public function getCreateOrderFrom()
    {
        do {
            if (empty($this->couponOrderSid)) {
                break;
            }
            if (empty($this->couponOrderSid->from)) {
                break;
            }
            return $this->couponOrderSid->from;

        } while (false);


        return CouponOrderSid::FROM_H5;
    }


}